package com.tywj.lib.core.common.util

import android.text.TextUtils
import android.util.Log
import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.LogStrategy
import com.orhanobut.logger.Logger
import com.orhanobut.logger.PrettyFormatStrategy
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.StringReader
import java.io.StringWriter
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerException
import javax.xml.transform.TransformerFactory
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.stream.StreamSource

/**
 * <pre>
 *     author : June Yang
 *     time   : 2020/5/7
 *     desc   : 日志工具类
 *     version: 1.0.0
 * </pre>
 */
object LogUtil {

    // 日志等级
    const val LEVEL_NONE = 0
    const val LEVEL_ERROR = 1
    const val LEVEL_WARN = 2
    const val LEVEL_INFO = 3
    const val LEVEL_DEBUG = 4
    const val LEVEL_VERBOSE = 5

    // json格式化打印缩进空格数
    private const val JSON_INDENT = 2

    // 当前日志tag
    var TAG = "PandaLog"
        private set

    // 当前日志等级
    private var curLevel = LEVEL_VERBOSE

    /**
     * 是否显示日志
     */
    private fun isLog(level: Int): Boolean {
        return level <= curLevel
    }

    /**
     * 初始化日志打印
     */
    fun init(tag: String = TAG, methodCount: Int = 3) {
        TAG = tag
        val formatStrategy = PrettyFormatStrategy.newBuilder()
            .showThreadInfo(true)
            .methodCount(methodCount)
            .methodOffset(2)
            .logStrategy(DynamicTagStrategy())
            .tag(tag)
            .build()
        Logger.addLogAdapter(AndroidLogAdapter(formatStrategy))
    }

    /**
     * 设置打印日志级别
     */
    fun setLevel(level: Int) {
        if (level in 0..5) {
            curLevel = level
        } else {
            throw IllegalArgumentException("wrong log level")
        }
    }

    fun stopLog() {
        curLevel =
            LEVEL_NONE
    }

    /**
     * 打印详细信息日志
     */
    fun v(msg: Any, useLogger: Boolean = true) {
        if (isLog(LEVEL_VERBOSE)) {
            if (useLogger) {
                Logger.v(msg.toString())
            } else {
                logWithPrefix(Log.VERBOSE, TAG, msg.toString())
            }
        }
    }

    /**
     * 打印调试日志
     */
    fun d(msg: Any, useLogger: Boolean = true) {
        if (isLog(LEVEL_DEBUG)) {
            if (useLogger) {
                Logger.d(msg.toString())
            } else {
                logWithPrefix(Log.DEBUG, TAG, msg.toString())
            }
        }
    }

    /**
     * 打印状态信息日志
     */
    fun i(msg: Any, useLogger: Boolean = true) {
        if (isLog(LEVEL_INFO)) {
            if (useLogger) {
                Logger.i(msg.toString())
            } else {
                logWithPrefix(Log.INFO, TAG, msg.toString())
            }
        }
    }

    /**
     * 打印警告日志
     */
    fun w(msg: Any, useLogger: Boolean = true) {
        if (isLog(LEVEL_WARN)) {
            if (useLogger) {
                Logger.w(msg.toString())
            } else {
                logWithPrefix(Log.WARN, TAG, msg.toString())
            }
        }
    }

    /**
     * 打印错误日志
     */
    fun e(msg: Any, useLogger: Boolean = true) {
        if (isLog(LEVEL_ERROR)) {
            if (useLogger) {
                Logger.e(msg.toString())
            } else {
                logWithPrefix(Log.ERROR, TAG, msg.toString())
            }
        }
    }

    /**
     * 打印json日志
     */
    fun json(jsonStr: String, useLogger: Boolean = true) {
        var json = jsonStr
        if (isLog(LEVEL_DEBUG)) {
            if (TextUtils.isEmpty(json)) {
                v("Empty/Null json content", useLogger)
                return
            }
            try {
                json = json.trim { it <= ' ' }
                if (json.startsWith("{")) {
                    val jsonObject = JSONObject(json)
                    val message = jsonObject.toString(JSON_INDENT)
                    v(message, useLogger)
                    return
                }
                if (json.startsWith("[")) {
                    val jsonArray = JSONArray(json)
                    val message = jsonArray.toString(JSON_INDENT)
                    v(message, useLogger)
                    return
                }
                v(jsonStr, useLogger)
            } catch (e: JSONException) {
                v(jsonStr, useLogger)
            }
        }
    }

    /**
     * 打印xml日志
     */
    fun xml(xml: String, useLogger: Boolean = true) {
        if (isLog(LEVEL_DEBUG)) {
            if (TextUtils.isEmpty(xml)) {
                v("Empty/Null xml content", useLogger)
                return
            }
            try {
                val xmlInput = StreamSource(StringReader(xml))
                val xmlOutput = StreamResult(StringWriter())
                val transformer = TransformerFactory.newInstance().newTransformer()
                transformer.setOutputProperty(OutputKeys.INDENT, "yes")
                transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")
                transformer.transform(xmlInput, xmlOutput)
                v(xmlOutput.writer.toString().replaceFirst(">".toRegex(), ">\n"), useLogger)
            } catch (e: TransformerException) {
                v(xml, useLogger)
            }
        }
    }

    fun printStackTrace(t: Throwable) {
        if (isLog(LEVEL_ERROR)) {
            t.printStackTrace()
            e(t)
        }
    }

    // tag 前缀，解决 Android3.1 Logcat 会合并短时间内同tag日志的问题
    private val prefix = arrayOf(". ", " .")
    private var index = 0

    private fun logWithPrefix(priority: Int, tag: String, message: String) {
        index = index xor 1
        Log.println(priority, prefix[index] + tag, message)
    }

    class DynamicTagStrategy : LogStrategy {
        override fun log(priority: Int, tag: String?, message: String) {
            logWithPrefix(priority, tag ?: TAG, message)
        }
    }
}